package com.fadis.cmd;

import com.fadis.FadisException;
import com.fadis.data.FList;
import com.fadis.data.base.StringList;
import com.fadis.db.FadisDB;
import com.fadis.protocol.BulkString;
import com.fadis.protocol.LongNumber;
import com.fadis.protocol.RespArray;
import com.fadis.protocol.SimpleString;

import java.util.ArrayList;
import java.util.List;

public class CmdList {

    // LPUSH key value [value …]
    // 返回新长度，类型错误error
    // LPUSH mylist a b c   ==> 相当于push a, push b, push c, 最后是c在表头
    public static final class lpush implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);


            StringList list = FadisDB.tryToGetOrCreateList( key, true);

            for (int i = 2; i < frame.getArgsCount(); i++) {
                FList.lpush(list, frame.getArg(i));
            }

            return LongNumber.encodeInt(list.size());

        }
    }

    // LPUSHX key value
    // 当且仅当 key 存在并且是一个列表
    // 返回新长度，类型错误error
    public static final class lpushx implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            StringList list = FadisDB.tryToGetOrCreateList( key, false);

            if(list == null) return LongNumber.encodeInt(0);

            for (int i = 2; i < frame.getArgsCount(); i++) {
                FList.lpush(list, frame.getArg(i));
            }

            return LongNumber.encodeInt(list.size());
        }
    }

    // RPUSH key value [value …]
    // 返回新长度，类型错误error
    public static final class rpush implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            StringList list = FadisDB.tryToGetOrCreateList( key, true);

            for (int i = 2; i < frame.getArgsCount(); i++) {
                FList.rpush(list, frame.getArg(i));
            }

            return LongNumber.encodeInt(list.size());
        }
    }

    // RPUSHX key value
    public static final class rpushx implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            StringList list = FadisDB.tryToGetOrCreateList( key, false);

            if(list == null) return LongNumber.encodeInt(0);

            for (int i = 2; i < frame.getArgsCount(); i++) {
                FList.rpush(list, frame.getArg(i));
            }

            return LongNumber.encodeInt(list.size());
        }
    }

    // LPOP key
    // 移除并返回，列表无或空返回null，类型错误error
    // -- 列表元素都被删了，对应的key也会被删除
    public static final class lpop implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            StringList list = FadisDB.tryToGetOrCreateList( key, false);
            if(list == null || list.size() == 0){
                return BulkString.encodedNull();
            }
            String item = FList.lpop(list);
            if(list.size() == 0){
                FadisDB.remove(key);
            }
            return BulkString.encodedBulkString(item);
        }
    }

    // RPOP key
    // 移除并返回，列表无或空返回null，类型错误error
    // -- 列表元素都被删了，对应的key也会被删除
    public static final class rpop implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);

           
            StringList list = FadisDB.tryToGetOrCreateList( key, false);
            if(list == null || list.size() == 0){
                return BulkString.encodedNull();
            }
            String item = FList.rpop(list);
            if(list.size() == 0){
                FadisDB.remove(key);
            }
            return BulkString.encodedBulkString(item);
        }
    }

    // RPOPLPUSH source destination
    // 返回被弹出的元素，
    // source无，空，直接返回
    // source类型错误
    // dest无则新建
    // dest类型错误
    // -- 列表元素都被删了，对应的key也会被删除
    public static final class rpoplpush implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String srckey = frame.getArg(1);
            String dstkey = frame.getArg(2);

            StringList list1 = FadisDB.tryToGetOrCreateList( srckey, false);
            if(list1 == null || list1.size() == 0){
                return BulkString.encodedNull();
            }

            StringList list2 = FadisDB.tryToGetOrCreateList( dstkey, true);
            String s = FList.rpop_lpush(list1, list2);

            if(list1.size() == 0){
                FadisDB.remove(srckey);
            }

            return BulkString.encodedBulkString(s);
        }
    }

    // LREM key count value
    // 返回被移除元素的数量，无或空返回0，类型错误
    // 移除值为value的元素，
    // count的符号表示方向，负数是从表头开始，正数是从表尾开始
    // count的绝对值表示删除几个
    // count是0表示都删除，方向也就无所谓了
    // -- 列表元素都被删了，对应的key也会被删除
    public static final class lrem implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String countStr = frame.getArg(2);
            String value = frame.getArg(3);
            int count = Integer.parseInt(countStr);

            StringList list = FadisDB.tryToGetOrCreateList( key, false);
            if(list == null){
                return LongNumber.encodeInt(0);
            }else{
                int c = FList.lrem(list, (int)count, value);
                if(list.size() == 0){
                    FadisDB.remove(key);
                }
                return LongNumber.encodeInt(c);
            }
        }
    }

    // LLEN key
    // 返回列表 key 的长度，无或空都是0
    public static final class llen implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            StringList list = FadisDB.tryToGetOrCreateList( key, false);
            return LongNumber.encodeInt(FList.len(list));
        }
    }

    // LINDEX key index
    // 返回下标元素，或者null，或者类型error
    public static final class lindex implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String indexStr = frame.getArg(2);
            int index = Integer.parseInt(indexStr);

            StringList list = FadisDB.tryToGetOrCreateList( key, false);
            String s = FList.lindex(list, (int)index);
            return BulkString.encodedBulkString(s);
        }
    }

    // LINSERT key BEFORE|AFTER pivot value
    // 将值 value 插入到列表 key 当中，位于值 pivot 之前或之后
    // 成功：返回列表新长度
    // 无或空：返回0
    // pivot找不到，插入失败：返回-1
    public static final class linsert implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String direct = frame.getArg(2);
            direct = direct.toLowerCase();
            String pivot = frame.getArg(3);
            String value = frame.getArg(4);

            StringList list = FadisDB.tryToGetOrCreateList( key, false);
            if(list == null || list.size() == 0){
                return LongNumber.encodeInt(0);
            }
            if(direct.equals("before")){
                int r = FList.linsertBefore(list, pivot, value);
                return LongNumber.encodeInt(r);
            }else if(direct.equals("after")){
                int r = FList.linsertAfter(list, pivot, value);
                return LongNumber.encodeInt(r);
            }else{
                throw new FadisException(4005, "错误的命令选项-" + direct);
            }
        }
    }

    // LSET key index value
    // 操作成功返回 ok  -- 不会增加长度，这是替换，所以下标就是[0, len-1]
    // 无或空：error
    // 下标超限：error
    public static final class lset implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String indexStr = frame.getArg(2);
            String value = frame.getArg(3);
            int index = Integer.parseInt(indexStr);

            StringList list = FadisDB.tryToGetOrCreateList( key, false);
            String s = FList.lset(list, (int)index, value);
            return SimpleString.encodedSimpleString("OK");
        }
    }

    // LRANGE key start stop
    // 返回列表或者空列表
    public static final class lrange implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String startStr = frame.getArg(2);
            String stopStr = frame.getArg(3);
            long start = Long.parseLong(startStr);
            long stop = Long.parseLong(stopStr);

            StringList list = FadisDB.tryToGetOrCreateList( key, false);
            List<String> sublist = FList.lrange(list, (int)start, (int)stop);
            if(sublist == null){
                sublist = new ArrayList<>();
            }
            return RespArray.encodeList(sublist);
        }
    }

    // LTRIM key start stop
    // 保留[start, stop], 执行命令 LTRIM list 0 2 ，表示只保留列表 list 的前三个元
    // 下标范围都超限的话，就是清空列表了
    // -- 列表元素都被删了，对应的key也会被删除
    // 命令执行成功时，返回 ok
    public static final class ltrim implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            String startStr = frame.getArg(2);
            String stopStr = frame.getArg(3);
            int start = Integer.parseInt(startStr);
            int stop = Integer.parseInt(stopStr);

            StringList list = FadisDB.tryToGetOrCreateList( key, false);
            if(list == null) return SimpleString.encodedSimpleString("OK");
            String s = FList.trim(list, (int) start, (int) stop);

            if(list.size() == 0){
                FadisDB.remove(key);
            }

            return SimpleString.encodedSimpleString("OK");
        }
    }

    public static final class blpop implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            StringList list = FadisDB.tryToGetOrCreateList( key, true);

            return null;
        }
    }

    public static final class brpop implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            StringList list = FadisDB.tryToGetOrCreateList( key, true);

            return null;
        }
    }

    public static final class brpoplpush implements CmdHandler{
        @Override
        public String run(FadisActionFrame frame) throws FadisException {
            String key = frame.getArg(1);
            StringList list = FadisDB.tryToGetOrCreateList( key, true);

            return null;
        }
    }

}
